﻿namespace CRM2011InternalEmail.Workflow
{
    using Entities;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Xrm.Sdk.Workflow;
    using System;
    using System.Activities;
    using System.Linq;
    using System.ServiceModel;

    public sealed class GetSalesOrderClose : CodeActivity
    {
        /// <summary>
        /// Executes the workflow activity.
        /// </summary>
        /// <param name="executionContext">The execution context.</param>
        protected override void Execute(CodeActivityContext executionContext)
        {
            // Create the tracing service
            ITracingService tracingService = executionContext.GetExtension<ITracingService>();

            if (tracingService == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
            }

            tracingService.Trace("Entered GetSalesOrderClose.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
                executionContext.ActivityInstanceId,
                executionContext.WorkflowInstanceId);

            // Create the context
            IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

            if (context == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
            }

            tracingService.Trace("GetSalesOrderClose.Execute(), Correlation Id: {0}, Initiating User: {1}",
                context.CorrelationId, context.InitiatingUserId);

            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            try
            {
                SalesOrder order = (SalesOrder)service.Retrieve(SalesOrderToFind.Get(executionContext).LogicalName, SalesOrderToFind.Get(executionContext).Id, new ColumnSet(true));

                EntityCollection closes = GetSalesOrderCloses(service, order.Id);

                if (closes.Entities.Count == 0)
                {
                    SalesOrderCloseDesc.Set(executionContext, string.Empty);
                    return;
                }

                bool firstOrLast = FirstOrLast.Get(executionContext);

                if (firstOrLast)
                {
                    OrderClose close = (OrderClose)closes.Entities.First();
                    SalesOrderCloseDesc.Set(executionContext, close.Description);
                }
                else
                {
                    OrderClose close = (OrderClose)closes.Entities.Last();
                    SalesOrderCloseDesc.Set(executionContext, close.Description);
                }
            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                tracingService.Trace("Exception: {0}", e.ToString());
                throw;
            }

            tracingService.Trace("Exiting GetSalesOrderClose.Execute(), Correlation Id: {0}", context.CorrelationId);
        }

        private EntityCollection GetSalesOrderCloses(IOrganizationService service, Guid id)
        {
            //Query for the sales order closes
            QueryExpression query = new QueryExpression()
            {
                EntityName = OrderClose.EntityLogicalName,
                ColumnSet = new ColumnSet(true),
                LinkEntities = 
                    {
                        new LinkEntity
                        {
                            LinkFromEntityName = OrderClose.EntityLogicalName,
                            LinkFromAttributeName = "salesorderid",
                            LinkToEntityName = SalesOrder.EntityLogicalName,
                            LinkToAttributeName = "salesorderid",
                            LinkCriteria = new FilterExpression
                            {
                                FilterOperator = LogicalOperator.And,
                                Conditions = 
                                {
                                    new ConditionExpression
                                    {
                                        AttributeName = "salesorderid",
                                        Operator = ConditionOperator.Equal,
                                        Values = { id }
                                    }
                                }
                            }
                        }
                    }
            };

            return service.RetrieveMultiple(query);
        }

        [RequiredArgument]
        [Input("SalesOrder With Close")]
        [ReferenceTarget("salesorder")]
        public InArgument<EntityReference> SalesOrderToFind { get; set; }

        [RequiredArgument]
        [Input("Retrieve First (True) Or Last (False) Close")]
        public InArgument<bool> FirstOrLast { get; set; }

        [OutputAttribute("Sales Order Close")]
        public OutArgument<string> SalesOrderCloseDesc { get; set; }
    }
}